import { pool } from '../database/config'

export abstract class BaseModel {
  // 检查连接是否有效
  private static async checkConnection(): Promise<boolean> {
    try {
      const connection = await pool.getConnection()
      await connection.ping()
      connection.release()
      return true
    } catch (error) {
      console.warn('数据库连接检查失败，尝试重连...')
      return false
    }
  }

  // 清理参数，将 undefined 转换为 null，并确保数字参数为整数
  private static cleanParams(params: any[]): any[] {
    return params.map(param => {
      if (param === undefined) return null
      
      // 对于所有数字参数，强制转换为整数（特别是 LIMIT 和 OFFSET）
      if (typeof param === 'number') {
        // 确保是安全的整数，避免超出 MySQL 整数范围
        if (Number.isSafeInteger(param)) {
          return Math.floor(param)
        }
        // 对于超出安全整数范围的数字，转换为字符串
        return param.toString()
      }
      
      // 对于字符串数字，转换为整数
      if (typeof param === 'string' && !isNaN(Number(param))) {
        const num = Number(param)
        if (Number.isSafeInteger(num)) {
          return Math.floor(num)
        }
        // 对于超出安全整数范围的数字，保持字符串形式
        return param
      }
      
      // 对于 BigInt 类型，转换为字符串（避免超出 JavaScript 安全整数范围）
      if (typeof param === 'bigint') {
        return param.toString()
      }
      
      return param
    })
  }

  // 带重试机制的查询方法
  static async query<T>(sql: string, params: any[] = []): Promise<T[]> {
    const maxRetries = 3
    let lastError: any = null

    for (let attempt = 1; attempt <= maxRetries; attempt++) {
      try {
        // 在重试时检查连接状态
        if (attempt > 1 && !(await this.checkConnection())) {
          console.log(`第 ${attempt} 次重试: 连接检查失败`)
          continue
        }

        const cleanedParams = this.cleanParams(params)
        // console.log(`sql: ${sql}, params: ${cleanedParams}`);
        
        const [rows] = await pool.execute(sql, cleanedParams)
        return [rows] as T[]
      } catch (error: any) {
        lastError = error
        
        // 如果是连接错误且不是最后一次尝试，则等待后重试
        if (error.code === 'ECONNRESET' || error.code === 'PROTOCOL_CONNECTION_LOST') {
          if (attempt < maxRetries) {
            console.warn(`数据库连接错误，第 ${attempt} 次重试...`)
            await new Promise(resolve => setTimeout(resolve, 1000 * attempt)) // 指数退避
            continue
          }
        }
        
        // 其他错误或达到最大重试次数
        break
      }
    }

    console.error('数据库查询错误，重试失败:', lastError)
    throw new Error(lastError instanceof Error ? lastError.message : '数据库查询失败')
  }

  // 带重试机制的执行方法
  static async execute(sql: string, params: any[] = []): Promise<any> {
    const maxRetries = 3
    let lastError: any = null

    for (let attempt = 1; attempt <= maxRetries; attempt++) {
      try {
        // 在重试时检查连接状态
        if (attempt > 1 && !(await this.checkConnection())) {
          console.log(`第 ${attempt} 次重试: 连接检查失败`)
          continue
        }

        const cleanedParams = this.cleanParams(params)
        const [result] = await pool.execute(sql, cleanedParams)
        return result
      } catch (error: any) {
        lastError = error
        
        // 如果是连接错误且不是最后一次尝试，则等待后重试
        if (error.code === 'ECONNRESET' || error.code === 'PROTOCOL_CONNECTION_LOST') {
          if (attempt < maxRetries) {
            console.warn(`数据库连接错误，第 ${attempt} 次重试...`)
            await new Promise(resolve => setTimeout(resolve, 1000 * attempt)) // 指数退避
            continue
          }
        }
        
        // 其他错误或达到最大重试次数
        break
      }
    }

    console.error('数据库执行错误，重试失败:', lastError)
    throw new Error(lastError instanceof Error ? lastError.message : '数据库执行失败')
  }

  static async create(data: any): Promise<any> {
    // 基础创建方法，需要在子类中实现具体逻辑
    throw new Error('Method not implemented')
  }

  static async update(id: number | string, data: any): Promise<boolean> {
    // 基础更新方法，需要在子类中实现具体逻辑
    throw new Error('Method not implemented')
  }

  static async delete(id: number | string): Promise<boolean> {
    // 基础删除方法，需要在子类中实现具体逻辑
    throw new Error('Method not implemented')
  }

  static async findById(id: number | string): Promise<any> {
    // 基础查找方法，需要在子类中实现具体逻辑
    throw new Error('Method not implemented')
  }
}